package com.demo.util;

import cn.hutool.core.lang.Validator;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;

/**
 * IP相关操作类
 *
 * @author wangfengchen
 */
@Slf4j
public class IpUtil {


  private static final String UNKNOWN = "unknown";

  /**
   * 获取ip
   *
   * @param request
   * @return
   */
  public static String getIpAddr(HttpServletRequest request) {
    String ipAddress;
    try {
      ipAddress = request.getHeader("x-forwarded-for");
      if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {
        ipAddress = request.getHeader("Proxy-Client-IP");
      }
      if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {
        ipAddress = request.getHeader("WL-Proxy-Client-IP");
      }
      if (ipAddress == null || ipAddress.length() == 0 || UNKNOWN.equalsIgnoreCase(ipAddress)) {
        ipAddress = request.getRemoteAddr();
        if (ipAddress.equals("127.0.0.1")) {
          // 根据网卡取本机配置的IP
          InetAddress inet = InetAddress.getLocalHost();
          if (inet != null) {
            ipAddress = inet.getHostAddress();
          }
        }
      }
      // 对于通过多个代理的情况，第一个IP为客户端真实IP,多个IP按照','分割
      // "***.***.***.***".length()
      if (ipAddress != null && ipAddress.length() > 15 && (ipAddress.indexOf(",")) > 0) {
        ipAddress = ipAddress.substring(0, ipAddress.indexOf(","));
      }
    } catch (Exception e) {
      ipAddress = "";
    }
    return ipAddress;
  }

  /**
   * 将整数转换成字符串ip
   *
   * @param ip 整数ip地址
   */
  public static String convertIpString(Integer ip) {
    if (ip == null) {
      return null;
    }
    int ipAddress = ip;
    int temp = ipAddress & 255;
    return String.valueOf(temp) + '.' + (ipAddress >> 8 & 255) + '.' + (ipAddress >> 16 & 255) + '.' +
        (ipAddress >> 24 & 255);
  }

  /**
   * 将ip转换成整数
   *
   * @param ip xxx.xx.xx.xx规则的ip地址
   */
  public static Integer convertIpInteger(String ip) {
    int result = 0;
    if (ip == null) {
      return null;
    } else {
      try {
        String ex = ip;
        int offset = 0;
        int number;
        for (number = 0; number < 3; ++number) {
          int index = ex.indexOf(46);
          if (index == -1) {
            return null;
          }
          String numberStr = ex.substring(0, index);
          int number1 = Integer.parseInt(numberStr);
          if (number1 < 0 || number1 > 255) {
            return null;
          }
          result += number1 << offset;
          offset += 8;
          ex = ex.substring(index + 1);
        }
        if (ex.length() > 0) {
          number = Integer.parseInt(ex);
          if (number >= 0 && number <= 255) {
            result += number << offset;
            return result;
          } else {
            return null;
          }
        } else {
          return null;
        }
      } catch (Exception e) {
        return null;
      }
    }
  }


  /**
   * 拼接国家区域编码
   *
   * @param countryIsoCode
   * @param subdivision1IsoCode
   * @param subdivision2IsoCode
   * @return
   */
  public static String jointCountryAreaCode(String countryIsoCode, String subdivision1IsoCode, String subdivision2IsoCode) {
    if (StringUtils.isBlank(countryIsoCode)) {
      countryIsoCode = "0";
    }
    if (StringUtils.isBlank(subdivision1IsoCode)) {
      subdivision1IsoCode = "0";
    }
    if (StringUtils.isBlank(subdivision2IsoCode)) {
      subdivision2IsoCode = "0";
    }
    return countryIsoCode.concat("_").concat(subdivision1IsoCode).concat("_").concat(subdivision2IsoCode);
  }

  /**
   * 判断Ip地址是否在ip白名单或黑名单, 仅支持验证ipv4地址并且 最后一位是 *
   *
   * @param ip
   * @param ipConfigList
   * @return
   */
  public static boolean checkIpv4List(String ip, String ipConfigList) {
    if (StringUtils.isBlank(ip) || !Validator.isIpv4(ip)) {
      log.info("ip地址为空或不是ipv4地址: {}", ip);
      return false;
    }
    if (StringUtils.isBlank(ipConfigList) || StringUtils.equals("*", ipConfigList) || StringUtils.equals(ip, ipConfigList)) {
      return true;
    }
    String[] array = StringUtils.split(ipConfigList, ",；;，");
    if (array == null || array.length == 0) {
      log.info("ip白/黑名单配置错误:  config={}", ipConfigList);
      return false;
    }

    Set<String> set = new HashSet<>(Arrays.asList(array));
    String[] ipArray = StringUtils.split(ip, '.');
    for (String ipConfig : set) {
      if (StringUtils.equals(ip, ipConfig)) {
        return true;
      }
      if (IpUtil.checkIpScope(ipArray, ipConfig)) {
        return true;
      }
    }
    log.info("ip白/黑名单拦截 : ip={}, config={}", ip, ipConfigList);
    return false;
  }

  /**
   * 判断Ip地址是否在ip白名单或黑名单, 仅支持最后一位是 * , 子方法
   *
   * @param ipArray
   * @param ipConfig
   * @return
   */
  private static boolean checkIpScope(String[] ipArray, String ipConfig) {
    if (StringUtils.isBlank(ipConfig) || !ipConfig.endsWith("*")) {
      return false;
    }
    String[] configArray = StringUtils.split(ipConfig, ".");
    if (configArray.length != 4) {
      return false;
    }
    for (int i = 0; i < 3; i++) {
      if (!StringUtils.equals(ipArray[i], configArray[i])) {
        return false;
      }
    }
    return true;
  }

  public static void main(String[] args) {
    String ip = "10.108.4.182";
    Integer ipInteger = convertIpInteger(ip);
    log.info("ipInteger = {}", ipInteger);
    String ipString = convertIpString(ipInteger);
    log.info("ipString = {}", ipString);
  }


}
